//
// Created by wlk12 on 2023/3/17.
//
#include <iostream>
#include <tuple>
#include <string>
#include <variant>
#include <vector>

template<typename V, typename... T>
void bprintf(V&& value, T&&... args) // base function
{
   std::cout << value << ", ";
   if constexpr (sizeof...(args) > 0)
   {
       bprintf(std::forward<T>(args)...);
   }
}

template<typename... T>
void tprintf(T&&... args) // recursive variadic function
{
    std::cout << "tprintf: ";
    bprintf(std::forward<T>(args)...);
    std::cout << std::endl;
}

template<typename ...T>
void printFun(T&&... a)
{
    std::cout << "printFun: ";
//    int _[]{(std::cout << a << "", 0)...};

    // C++ 17
    ((std::cout << a << ", "), ...);
    std::cout << std::endl;
}

template<typename... Ts>
void func(Ts... args)
{
    std::cout << "args count:" << sizeof...(args) << std::endl;

    // since initializer lists guarantee sequencing, this can be used to
    // call a function on each element of a pack, in order:
    char dummy[] = {(args, true)...};
    std::cout << "args count2:"  << sizeof(dummy)<< std::endl;
}

// https://en.cppreference.com/w/cpp/language/fold
// https://en.cppreference.com/w/cpp/utility/apply
template<typename... Ts>
void funTuple(Ts... args)
{
    std::tuple<Ts...> tuple(args...);

    std::cout << "funTuple: ";
    std::apply([](auto&&... args) {((std::cout << args << ", "), ...);}, tuple);
    std::cout << std::endl;
}

// https://en.cppreference.com/w/cpp/language/fold
template<typename... T>
void add(T... num)
{
    double sum = (static_cast<double>(num) + ...) ;
    std::cout << "add: " << sum << std::endl;
}

template<typename T>
void print(const T& value)
{
    std::cout << value << " ";
}
template<typename... T>
void printAll(T&& ...args)
{
    std::cout << "printAll: ";
    (print(args), ...);
    std::cout << std::endl;
}

int main()
{
    tprintf(1, 2, 3, "abc");

    printFun(1, 2.01, "abc");

    func(1, 2, 3, "abc", 5);

    funTuple(1, 2, 3, "abc", 5);

    add(1, 5.2f, 5, 10.1);

    printAll(1, 2, 3, "abc", 5);

    std::cout << "-------------------" << std::endl;
    std::tuple<int, std::string, int> tuple;
    tuple = {1, "abc", 2};

    std::variant<int, std::string, double, std::vector<int>> variantData;
    std::cout<< "sizeof std::variant<int, std::string, double, std::vector<int>>: " << sizeof(variantData) << std::endl;

    int n = 10;
    const char* cstr = "abcd";

    auto* fp = (float*)(&n);
    auto* fp2 = (float*) cstr;
    std::cout<< "fp= " << *fp  << " ，  fp2=" << *fp2 << std::endl;

    std::cout<< *reinterpret_cast<float*>(&n) << std::endl;


    return  0;
}

